#!/usr/bin/perl

use strict;

use constant NIL => undef;

sub cons {
    my ($x, $y) = @_;

    my @l = ($x);
    push @l, @{$y} if ($y);

    return \@l;
}

sub car {
    my $z = shift;

    return $$z[0];
}

sub cdr {
    my $z = shift;

    my @l = @$z;
    shift @l;

    return @l == 0 ? NIL : \@l;
}

sub null {
    my $list = shift;

    return ! defined $list;
}

sub make_list {
    my @items = @_;

    return undef if ( @items == 0);

    my $first_item = shift @items;

    return cons($first_item, make_list(@items));
}

sub list_ref {
    my ($list, $n) = @_;

    if ( $n == 0 ) { return car($list); }
    else {
        return list_ref( cdr($list), $n-1 );
    }
}

sub list_length {
    my $list = shift;

    return 0 if ( null($list) );
    return 1 + list_length( cdr($list) );
}

my $list1 = cons(1, cons(2, cons(3, cons(4, cons(5, (cons(6)))))));
my $len1 = list_length($list1);

print "length is $len1\n";
for my $index (0 .. $len1-1) {
    print list_ref($list1, $index) . "\n";
}

my $list2 = make_list(1, 2, 3, 4, 5, 6, 'a', 'b', 'c', 'd', 'e');

my $len2 = list_length($list2);

print "length is $len2\n";
for my $index (0 .. $len2-1) {
    print list_ref($list2, $index) . "\n";
}

